#include "ComTest.h"

HRESULT __stdcall CCOM_OBJECT::QueryInterface(const IID &iid, void **iface)
{
	// this function basically casts the this pointer or the Iunknown
	// pointer into the interface requested, notice the comparison with
	// the GUIDs generated and defined in the begining of the program

	// requesting the IUnknown base interface
	if (iid==IID_IUnknown)
	{
		std::cout << "Requesting IUnknown interface" << std::endl;
		*iface = (IX*)this;

	} // end if

	// maybe IX?
	if (iid==IID_IX)
	{
		std::cout << "Requesting IX interface" << std::endl;
		*iface = (IX*)this;

	} // end if
	else  // maybe IY
		if (iid==IID_IY)
		{
			std::cout << "Requesting IY interface" << std::endl;
			*iface = (IY*)this;

		} // end if
		else
		{ // cant find it!
			std::cout << "Requesting unknown interaface!" << std::endl;
			*iface = NULL;
			return(E_NOINTERFACE);
		} // end else

		// if everything went well cast pointer to IUnknown and call addref()
		((IUnknown *)(*iface))->AddRef();

		return(S_OK);

} // end QueryInterface

////////////////////////////////////////////////////////////////////////////////////////////////

ULONG __stdcall CCOM_OBJECT::AddRef()
{
	// increments reference count
	std::cout << "Adding a reference" << std::endl;
	return(++ref_count);

} // end AddRef

///////////////////////////////////////////////////////////////////////////////////////////////

ULONG __stdcall CCOM_OBJECT::Release()
{
	// decrements reference count
	std::cout << "Deleting a reference" << std::endl;
	if (--ref_count==0)
	{
		delete this;
		return(0);
	} // end if
	else
		return(ref_count);

} // end Release

///////////////////////////////////////////////////////////////////////////////////////////////

IUnknown *CoCreateInstance(void)
{
	// this is a very basic implementation of CoCreateInstance()
	// it creates an instance of the COM object, in this case
	// I decided to start with a pointer to IX -- IY would have
	// done just as well

	IUnknown *comm_obj = (IX *)new(CCOM_OBJECT);

	std::cout << "Creating Comm object" << std::endl;

	// update reference count
	comm_obj->AddRef();

	return(comm_obj);

} // end CoCreateInstance

///////////////////////////////////////////////////////////////////////////////////////////////

void ComTest(void)
{
	// create the main COM object
	IUnknown *punknown = CoCreateInstance();

	// create two NULL pointers the the IX and IY interfaces
	IX *pix=NULL;
	IY *piy=NULL;

	// from the original COM object query for interface IX
	punknown->QueryInterface(IID_IX, (void **)&pix);

	// try some of the methods of IX
	pix->fx();

	// release the interface
	pix->Release();


	// now query for the IY interface
	punknown->QueryInterface(IID_IY, (void **)&piy);

	// try some of the methods
	piy->fy();

	// release the interface
	piy->Release();

	// release the COM object itself
	punknown->Release();
} // end main